package com.shop.cereshop.app.service.shop.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.shop.cereshop.app.dao.collect.CereBuyerCollectDAO;
import com.shop.cereshop.app.dao.location.CityDAO;
import com.shop.cereshop.app.dao.product.CereShopProductDAO;
import com.shop.cereshop.app.dao.shop.CereBusinessTimeDAO;
import com.shop.cereshop.app.dao.shop.CerePlatformShopDAO;
import com.shop.cereshop.app.dao.shop.CereShopBrandDAO;
import com.shop.cereshop.app.domain.product.ShopProductVO;
import com.shop.cereshop.app.domain.shop.CustomerServiceDTO;
import com.shop.cereshop.app.domain.shop.QueryShopDTO;
import com.shop.cereshop.app.domain.shop.ShopVO;
import com.shop.cereshop.app.param.shop.SearchShopParam;
import com.shop.cereshop.app.param.shop.SuggestShopParam;
import com.shop.cereshop.app.service.buyer.CereBuyerSearchService;
import com.shop.cereshop.app.service.buyer.CereBuyerShopCouponService;
import com.shop.cereshop.app.service.collect.CereBuyerCollectService;
import com.shop.cereshop.app.service.distributor.CereShopDistributorService;
import com.shop.cereshop.app.service.product.CereShopProductService;
import com.shop.cereshop.app.service.redis.LabelService;
import com.shop.cereshop.app.service.shop.*;
import com.shop.cereshop.app.utils.BusinessUtils;
import com.shop.cereshop.app.utils.DateUtils;
import com.shop.cereshop.commons.constant.CoReturnFormat;
import com.shop.cereshop.commons.constant.IntegerEnum;
import com.shop.cereshop.commons.domain.calculate.Calculate;
import com.shop.cereshop.commons.domain.collect.CereBuyerCollect;
import com.shop.cereshop.commons.domain.common.Page;
import com.shop.cereshop.commons.domain.shop.CereBusinessTime;
import com.shop.cereshop.commons.domain.shop.CereShopBrand;
import com.shop.cereshop.commons.exception.CoBusinessException;
import com.shop.cereshop.commons.result.Result;
import com.shop.cereshop.commons.upload.strategy.FileStrategy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class PlatformShopV2ServiceImpl implements PlatformShopV2Service {

    private final CerePlatformShopDAO cerePlatformShopDAO;
    private final CereShopProductDAO cereShopProductDAO;
    private final CereBusinessTimeDAO cereBusinessTimeDAO;
    private final CereBuyerCollectDAO cereBuyerCollectDAO;
    private final CereShopBrandDAO cereShopBrandDAO;
    private final LabelService labelService;

    @Override
    public Result<Page<ShopVO>> getSuggestShopList(SuggestShopParam param) {
        QueryShopDTO queryDTO = param.toQueryShopDTO();
        if (queryDTO == null) {
            log.error("转换suggest shop查询参数失败");
            return Result.failed(CoReturnFormat.PARAM_INVALID, "参数转换失败");
        }
        return getShopPageResult(queryDTO, "推荐", cerePlatformShopDAO::queryShopList);
    }

    @Override
    public Result<Page<ShopVO>> searchShopList(SearchShopParam param) {
        if (param.getDistance() != null && StringUtils.isBlank(param.getLocation())) {
            return Result.failed(CoReturnFormat.PARAM_MISSING, "请传参数location");
        }
        QueryShopDTO queryDTO = param.toQueryShopDTO();
        if (queryDTO == null) {
            log.error("转换search shop查询参数失败");
            return Result.failed(CoReturnFormat.PARAM_INVALID, "参数转换失败");
        }
        return getShopPageResult(queryDTO, "搜索", cerePlatformShopDAO::queryShopList);
    }

    @Override
    public Result<Page<ShopVO>> getCollectShopList(SearchShopParam param) {
        if (param.getDistance() != null && StringUtils.isBlank(param.getLocation())) {
            return Result.failed(CoReturnFormat.PARAM_MISSING, "请传参数location");
        }
        QueryShopDTO queryDTO = param.toQueryShopDTO();
        if (queryDTO == null) {
            log.error("转换collect shop查询参数失败");
            return Result.failed(CoReturnFormat.PARAM_INVALID, "参数转换失败");
        }
        return getShopPageResult(queryDTO, "收藏", cerePlatformShopDAO::getCollectShopList);
    }

    private Result<Page<ShopVO>> getShopPageResult(QueryShopDTO queryDTO, String typeDesc, Function<QueryShopDTO, List<ShopVO>> func) {
        PageHelper.startPage(queryDTO.getPage(), queryDTO.getPageSize());
        List<ShopVO> shopList = func.apply(queryDTO);
        if (CollUtil.isEmpty(shopList)) {
            log.warn("没有查询到{}店铺数据", typeDesc);
            return Result.success(new Page<>(new ArrayList<>(), 0L));
        }

        String week = DateUtils.currentDayOfWeek();
        List<Long> shopIds = shopList.stream().map(ShopVO::getShopId).collect(Collectors.toList());

        // 批量获取营业时间
        List<CereBusinessTime> allBusinessTimes = getAllShopBusinessTimeList(shopIds);
        Map<Long, List<CereBusinessTime>> businessTimeMap = allBusinessTimes.stream()
                .collect(Collectors.groupingBy(CereBusinessTime::getShopId));

        // 批量获取商品
        List<ShopProductVO> productList = cereShopProductDAO.getProductListByShopIds(shopIds, queryDTO.getShopType(), 4L);
        Map<Long, List<ShopProductVO>> productMap = productList.stream()
                .collect(Collectors.groupingBy(ShopProductVO::getShopId));

        // 批量获取服务标签
        Map<Long, Calculate> serviceLabelMap = labelService.getShopServiceLabelMap(shopIds);

        for (ShopVO shop : shopList) {
            long createTimeMs = shop.getCreateTime().toInstant(ZoneOffset.UTC).toEpochMilli();
            shop.setIsNewShop(BusinessUtils.judgeIsNewShop(createTimeMs));

            List<CereBusinessTime> shopBusinessTimeList = businessTimeMap.getOrDefault(shop.getShopId(), Collections.emptyList());
            shop.setBusinessTimes(shopBusinessTimeList);

            String businessTimeByWeek = BusinessUtils.getShopBusinessTimeByWeek(week, shopBusinessTimeList);
            shop.setAllDayToUse(BusinessUtils.judgeShopIsAllDayToUse(businessTimeByWeek));
            shop.setBusinessTime(businessTimeByWeek);

            List<ShopProductVO> products = productMap.getOrDefault(shop.getShopId(), Collections.emptyList());
            shop.setProducts(products);

            Calculate calculate = serviceLabelMap.get(shop.getShopId());
            shop.setServiceLabels(BusinessUtils.getShopServiceLabels(calculate));
        }

        PageInfo<ShopVO> pageInfo = new PageInfo<>(shopList);
        Page<ShopVO> pageResult = new Page<>(pageInfo.getList(), pageInfo.getTotal());
        return Result.success(pageResult);
    }

    @Override
    public Result<List<ShopVO>> shopHotList(String cityCode){
        List<ShopVO> shopHotList = cerePlatformShopDAO.getShopHotList(cityCode);
        if (CollUtil.isEmpty(shopHotList)) {
            log.warn("没有查询到热门店铺数据");
            return Result.success(Collections.emptyList());
        }
        return Result.success(shopHotList);
    }

    @Override
    public ShopVO getShopDetail(Long shopId, Integer shopType, Long buyerUserId, String cityCode) throws Exception {
        ShopVO shopVO = cerePlatformShopDAO.getShopById(shopId, shopType);
        if (shopVO == null) {
            throw new CoBusinessException(CoReturnFormat.MERCHANT_NOT_EXIST);
        }
        long createTime = shopVO.getCreateTime().getSecond() * 1000L;
        shopVO.setIsNewShop(BusinessUtils.judgeIsNewShop(createTime));

        // 营业时间
        List<CereBusinessTime> shopBusinessTimeList = getShopBusinessTimeList(shopId);
        shopVO.setBusinessTimes(shopBusinessTimeList);
        String week = DateUtils.currentDayOfWeek();
        String businessTimeByWeek = BusinessUtils.getShopBusinessTimeByWeek(week, shopBusinessTimeList);
        shopVO.setAllDayToUse(BusinessUtils.judgeShopIsAllDayToUse(businessTimeByWeek));
        shopVO.setBusinessTime(BusinessUtils.getShopBusinessTimeByWeek(week, shopBusinessTimeList));

        // 如果用户登录了，加上是否收藏店铺
        if (buyerUserId != null) {
            CereBuyerCollect buyerCollect = cereBuyerCollectDAO.findByUserShopId(buyerUserId, shopId);
            if (buyerCollect != null && IntegerEnum.YES.getCode().equals(buyerCollect.getState())) {
                shopVO.setIsCollect(IntegerEnum.YES.getCode());
                shopVO.setCollectId(buyerCollect.getCollectId());
            }
        }

        // 店铺品牌
        CereShopBrand shopBrand = cereShopBrandDAO.findByShopId(shopId);
        if (shopBrand != null) {
            shopVO.setIsBrand(IntegerEnum.YES.getCode());
            shopVO.setBrandName(shopBrand.getBrandName());
        }

        shopVO.setShopType(shopType);

        Calculate calculate = labelService.getShopServiceLabel(shopId);
        if (calculate != null) {
            shopVO.setServiceLabels(BusinessUtils.getShopServiceLabels(calculate));
        }
        shopVO.setCustomerService(new CustomerServiceDTO());
        return shopVO;
    }

    /**
     * 店铺营业时间列表
     *
     * @param shopId 店铺id
     *               return 店铺营业时间列表
     */
    private List<CereBusinessTime> getShopBusinessTimeList(Long shopId) {
        QueryWrapper<CereBusinessTime> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("shop_id", shopId);
        queryWrapper.orderByAsc("week");
        return cereBusinessTimeDAO.selectList(queryWrapper);
    }

    /**
     * 店铺营业时间列表
     *
     * @param shopIds 店铺id集合
     *                return 店铺营业时间列表
     */
    private List<CereBusinessTime> getAllShopBusinessTimeList(List<Long> shopIds) {
        QueryWrapper<CereBusinessTime> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("shop_id", shopIds);
        return cereBusinessTimeDAO.selectList(queryWrapper);
    }

    /**
     * 根据shopId分组，获取店铺营业时间
     *
     * @param shopId           店铺id
     * @param allBusinessTimes 所有店铺营业时间集合
     *                         return 返回店铺营业时间
     */
    private List<CereBusinessTime> getShopBusinessTimeList(Long shopId, List<CereBusinessTime> allBusinessTimes) {
        if (CollUtil.isEmpty(allBusinessTimes)) {
            return Collections.emptyList();
        }
        // bussinessTimes转成Map，根据shopId分组
        Map<Long, List<CereBusinessTime>> businessTimeMap = allBusinessTimes.stream()
                .collect(Collectors.groupingBy(CereBusinessTime::getShopId));
        return businessTimeMap.get(shopId);
    }

    /**
     * 店铺商品
     *
     * @param shopId      店铺id
     * @param shopType    店铺类型
     * @param allProducts 所有商品集合
     *                    return 返回店铺营业时间
     */
    private List<ShopProductVO> getShopProducts(Long shopId, Integer shopType, List<ShopProductVO> allProducts) {
        if (CollUtil.isEmpty(allProducts)) {
            return Collections.emptyList();
        }
        // allProducts转成Map，根据shopId分组, 同时要将shopType设置给ShopProductVO
        allProducts.forEach(product -> product.setShopType(shopType));
        Map<Long, List<ShopProductVO>> productMap = allProducts.stream().collect(Collectors.groupingBy(ShopProductVO::getShopId));
        return productMap.get(shopId);
    }



}
